class ProbHash
  
  attr_accessor :num_sticky
  
  def initialize
    @hash = {}
    @num_sticky = 0
  end
  
  def init(p = 0, doms)
    doms.each do |d|
      a = [d.head, d.tail].sort
      @hash[a] = ProbHashValue.new(p)
    end
  end
  
  def size
    @hash.keys.size
  end
  
  def set_sticky(d)
    
    arr = [d.head,d.tail].sort
    @hash[arr].sticky = true
    @num_sticky += 1
  end
  
  def remove(d)
    a = [d.head, d.tail].sort
    @num_sticky = @num_sticky - 1 if @hash[a] && @hash[a].sticky
    @hash.delete a
  end
  
  def reset_stickies(p)
    @hash.each do |k,v|
      @hash[k] = ProbHashValue.new(p, true) if v.sticky
    end
    @hash
  end
  
  def reset(p=nil, &block)
    if block_given?
      
      @hash.each do |k,v|
        yield @hash[k]
      end
      
    elsif p
      @hash.each do |k,v|
        @hash[k] = ProbHashValue.new(p) unless v.sticky
      end
    end
    @hash
  end
  
  def [](a,b)
    a = [a,b].sort
    @hash[a].value
  end
  
  def get(d)
    a = [d.head, d.tail].sort
    @hash[a]
  end
  
  def []= (a,b,c)
    arr = [a,b].sort
    @num_sticky += 1 unless @hash[arr] && @hash[arr].sticky 
    phv = ProbHashValue.new(c, true)
    @hash[arr] = phv
  end
  
  def to_s
    "#{@hash}"
  end
  
  def to_a
    @hash.to_a
  end
    
  def dup
    h = ProbHash.new
    
    dup_hash = @hash.inject({}) do |memo, kv| 
      key,value = kv[0], kv[1]
      arr = key.dup #safe to dup array with integers
      memo[arr] = value.dup #duplicate ProbHashValue 
      memo
    end
    
    h.send(:set_hash, dup_hash, @num_sticky)
    h
  end
  
  private
  
  def set_hash(h, ns)
    @num_sticky = ns
    @hash = h
  end
  
  class ProbHashValue
    
    attr_accessor :sticky, :value
    def initialize(v, s = false)
      @sticky = s
      @value = v
    end
    def to_s
      s = @value.to_s
      s << "*" if @sticky
      s
    end
    
    def dup
      ProbHashValue.new @value, @sticky
    end
  end
  
end